/*
配置阿里云签名  文档: https://help.aliyun.com/zh/api-gateway/user-guide/use-digest-authentication-to-call-an-api#topic-1867627
客户端需要从HTTP请求中生成的签名串 格式如下：
HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters
7个字段构成整个签名串，字段之间使用\n间隔，如果Headers为空，则不需要加\n，其他字段如果为空都需要保留\n。签名大小写敏感。
*/
import crtptoJs from 'crypto-js'
import {generateUUID} from "@/utils";

export const appkey = '204464704'
export const appsecret = 'rvrn3kxHpvxIXNz0jfu7R4d2qqa7WGCA'

export const signString = (params: { needApi: boolean, method: string; path: string; data: Record<string, any> }) => {
    let {method, path, data, needApi} = params

    let headerObj = {
        'x-ca-key': appkey,
        'x-ca-nonce': generateUUID(),
        'x-ca-signature-method': 'HmacSHA256'
    }

    let headerText = ''
    for (let [key, value] of Object.entries(headerObj)) {
        headerText += `${key.toLowerCase()}:${value}\n`
    }
    const contentType = isFormData(data) ? 'multipart/form-data' : 'application/json'

    if (method == 'post' && Object.keys(data).length > 0 && !isFormData(data)) {
        const encrypData = (crtptoJs.MD5(JSON.stringify(data))).toString(crtptoJs.enc.Base64)
        let signRes = needApi ? method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + encrypData + '\n' + contentType + '\n' + '\n' + headerText + '/api' + path : method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + encrypData + '\n' + contentType + '\n' + '\n' + headerText + path
        const enSign = (crtptoJs.HmacSHA256(signRes, appsecret)).toString(crtptoJs.enc.Base64)
        return {
            ...headerObj,
            'Accept': '*/*',
            'x-ca-signature': enSign,
            'x-ca-signature-headers': 'x-ca-key,x-ca-nonce,x-ca-signature-method',
            'content-md5': encrypData
        }
    }
    if (method == 'post' && Object.keys(data).length == 0 && !isFormData(data)) {
        const signRes = needApi ? method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + contentType + '\n' + '\n' + headerText + '/api' + path : method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + contentType + '\n' + '\n' + headerText + path
        const enSign = (crtptoJs.HmacSHA256(signRes, appsecret)).toString(crtptoJs.enc.Base64)
        return {
            ...headerObj,
            'Accept': '*/*',
            'x-ca-signature': enSign,
            'x-ca-signature-headers': 'x-ca-key,x-ca-nonce,x-ca-signature-method'
        }
    }
    if (method == 'post' && Object.keys(data).length == 0 && isFormData(data)) {
        const signRes = needApi ? method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + contentType + '\n' + '\n' + headerText + '/api' + path : method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + contentType + '\n' + '\n' + headerText + path
        const enSign = (crtptoJs.HmacSHA256(signRes, appsecret)).toString(crtptoJs.enc.Base64)
        return {
            ...headerObj,
            'Accept': '*/*',
            'x-ca-signature': enSign,
            'X-Ca-Signed-Content-Type': 'multipart/form-data',
            'x-ca-signature-headers': 'x-ca-key,x-ca-nonce,x-ca-signature-method'
        }
    }
    if (method == 'get' && Object.keys(data).length > 0) {
        const pathData = `${path}?${sortKeys(data)}`
        const signRes = needApi ? method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + '\n' + '\n' + headerText + '/api' + pathData : method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + '\n' + '\n' + headerText + pathData
        const enSign = (crtptoJs.HmacSHA256(signRes, appsecret)).toString(crtptoJs.enc.Base64)
        return {
            ...headerObj,
            'Accept': '*/*',
            'x-ca-signature': enSign,
            'x-ca-signature-headers': 'x-ca-key,x-ca-nonce,x-ca-signature-method',
        }
    }
    if (method == 'get' && Object.keys(data).length == 0) {
        const signRes = needApi ? method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + '\n' + '\n' + headerText + '/api' + path : method.toLocaleUpperCase() + '\n' + '*/*' + '\n' + '\n' + '\n' + '\n' + headerText + path
        const enSign = (crtptoJs.HmacSHA256(signRes, appsecret)).toString(crtptoJs.enc.Base64)
        return {
            ...headerObj,
            'Accept': '*/*',
            'x-ca-signature': enSign,
            'x-ca-signature-headers': 'x-ca-key,x-ca-nonce,x-ca-signature-method',
        }
    }
}
/**
 * @description {Function} sortKeys 序列化get请求参数
 * @param {object} data 请求参数
 * @author 花东红
 * @time 2024/1/10
 */
const sortKeys = (data: Record<string, any>) => {

    if (!Object.keys(data).length) return

    const sortKeysMap = Object.keys(data).sort()

    const sortParamsMap = sortKeysMap.map(v => ({[v]: data[v]})).reduce((result, obj) => {
        for (let key in obj) {
            result[key] = obj[key];
        }
        return result;
    }, {});

    return Object.entries(sortParamsMap).map(v => {
        if (v[1] !== 0 && !v[1]) {
            return v[0]
        }
        return `${v[0]}=${v[1]}`
    }).join('&')
}

/**
 * @description {Function} isFormData 判断请求参数是否是FormData
 * @param {object} data 请求参数
 * @author 花东红
 * @time 2024/1/10
 */
const isFormData = (data: Record<string, any>) => {
    return data instanceof FormData
}
